#ifndef __WIZ_UTILS_EVENT_TEMPLATE_HPP__SHANHAOBO_19800429__
#define __WIZ_UTILS_EVENT_TEMPLATE_HPP__SHANHAOBO_19800429__

#include "../../Base/WizBase.hpp"
#include "../../Core/Container/WizDataTypeMap.hpp"
#include "../../Core/Container/WizDataTypeMultiMap.hpp"

#include "../../DataType/Signal/WizDataTypeSignal.hpp"

namespace Wiz
{
    namespace Event
    {
        namespace Agency
        {
            template <class ParamT> class Type;
        } /// end of namespace Agency

        namespace Community
        {
            namespace Node
            {
                template <class ParamT> class Type;
            } /// end of namespace Node
            template <class ParamT> class Type;
        } /// end of namespace Community

        namespace Transfer
        {
            namespace Node
            {
                template <class ParamT> class Type;
            } /// end of namespace Node
            template <class ParamT> class Type;
        } /// end of namespace Transfer

        namespace Publisher
        {
            template <class ParamT> class Type;
        } /// end of namespace Publisher

        namespace Subscriber
        {
            template <class ParamT> class Type;
        } /// end of namespace Subscriber

        template <class ParamT> class Type;
    } /// end of namespace Event
} /// end of namespace Wiz

#endif /*__WIZ_UTILS_EVENT_TEMPLATE_HPP__SHANHAOBO_19800429__*/

#if defined(WIZ_EVENT_PARAM_COUNT) && (WIZ_EVENT_PARAM_COUNT >= 0) && (WIZ_EVENT_PARAM_COUNT < 255)

namespace Wiz
{
    namespace Event
    {
        namespace Subscriber
        {
            template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
            class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
            {
            public:
                Type()
                {
                }
            public:
                virtual ::Wiz::Void::Type EventRespond(WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
                {
                }
            };
        } /// end of namespace Subscriber

        namespace Publisher
        {
            template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
            class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))> : private ::Wiz::Signal::Safe::Type<::Wiz::Void::Type(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
            {
                typedef typename ::Wiz::Signal::Safe::Type<::Wiz::Void::Type(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>   tSuper;
            public:
                typedef typename ::Wiz::Event::Subscriber::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>           tSubscriber;
            public:
                Type() : tSuper()
                {
                }
            public:
                ::Wiz::Void::Type EventPublish(WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
                {
                    tSuper::SignalExecute(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, A));
                }
            public:
                ::Wiz::Void::Type Subscribe(const tSubscriber* SPtr)
                {
                    tSuper::Register(SPtr, &tSubscriber::EventRespond);
                }
                ::Wiz::Void::Type Unsubscribe(const tSubscriber* SPtr)
                {
                    tSuper::Unregister(SPtr, &tSubscriber::EventRespond);
                }
            public:
                template<class U>
                ::Wiz::Void::Type Subscribe(const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    tSuper::Register(C, FP);
                }
                template<class U>
                ::Wiz::Void::Type Unsubscribe(const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    tSuper::Unregister(C, FP);
                }
            };
        } /// end of namespace Publisher

        namespace Agency
        {
            template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
            class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
            {
            public:
                typedef typename ::Wiz::Event::Publisher::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>    tPublisher;
                typedef typename tPublisher::tSubscriber                                                            tSubscriber;
            public:
                typedef ::Wiz::MultiMap::Type<EvtT, tPublisher*>                                                    tPublisherMap;
            protected:
                tPublisherMap m_PublisherMap;
            public:
                Type()
                {}
            public:
                ::Wiz::Void::Type Register(const EvtT& E, tPublisher* PPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(PPtr));
                    m_PublisherMap.Insert(E, PPtr);
                }
                ::Wiz::Void::Type Unregister(const EvtT& E, tPublisher* PPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(PPtr));
                    tPublisherMap::tIterator Itr = m_PublisherMap.LowerBound(E);
                    tPublisherMap::tIteratorConst ItrEnd = m_PublisherMap.UpperBound(E);
                    for (; Itr != ItrEnd; Itr++)
                    {
                        if (Itr.GetValue() == PPtr)
                        {
                            m_PublisherMap.Erase(Itr);
                            return;
                        }
                    }
                }
            public:
                ::Wiz::Void::Type Subscribe(const EvtT& E, const tSubscriber* SPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(SPtr));
                    tPublisherMap::tIterator Found = m_PublisherMap.Find(E);
                    if (Found != m_PublisherMap.End())
                    {
                        Found.GetValue()->Register(SPtr);
                    }
                }
                ::Wiz::Void::Type Unsubscribe(const EvtT& E, const tSubscriber* SPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(SPtr));
                    tPublisherMap::tIterator Found = m_PublisherMap.Find(E);
                    if (Found != m_PublisherMap.End())
                    {
                        Found.GetValue()->Unregister(SPtr);
                    }
                }
            public:
                template<class U>
                ::Wiz::Void::Type Subscribe(const EvtT& E, const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(C));
                    tPublisherMap::tIterator Found = m_PublisherMap.Find(E);
                    if (Found != m_PublisherMap.End())
                    {
                        Found.GetValue()->Register(C, FP);
                    }
                }
                template<class U>
                ::Wiz::Void::Type Unsubscribe(const EvtT& E, const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(C));
                    tPublisherMap::tIterator Found = m_PublisherMap.Find(E);
                    if (Found != m_PublisherMap.End())
                    {
                        Found.GetValue()->Unregister(C, FP);
                    }
                }
            };
        } /// end of namespace Agency

        namespace Community
        {
            namespace Node
            {
                template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
                class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))> : public ::Wiz::Event::Subscriber::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
                {
                public:
                    typedef typename ::Wiz::Event::Publisher::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))> tPublisher;
                    typedef typename tPublisher::tSubscriber tSubscriber;
                protected:
                    tPublisher m_Publisher;
                public:
                    Type()
                    {}
                public:
                    ::Wiz::Void::Type Subscribe(const tSubscriber* SPtr)
                    {
                        WIZ_ASSERT(::Wiz::IsValidPtr(SPtr));
                        m_Publisher.Subscribe(SPtr);
                    }
                    ::Wiz::Void::Type Unsubscribe(const tSubscriber* SPtr)
                    {
                        WIZ_ASSERT(::Wiz::IsValidPtr(SPtr));
                        m_Publisher.Unsubscribe(SPtr);
                    }
                public:
                    virtual ::Wiz::Void::Type EventPublish(WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
                    {
                        m_Publisher.EventPublish(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, A));
                    }
                };
            } /// end of namespace Node

            template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
            class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
            {
            public:
                typedef typename ::Wiz::Event::Agency::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>           tSuper;
                typedef typename ::Wiz::Event::Publisher::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>        tPublisher;
                typedef typename ::Wiz::Event::Transfer::Node::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>   tNode;
                typedef typename tPublisher::tSubscriber                                                                tSubscriber;
            protected:
                typedef ::Wiz::Map::Type<EvtT, tNode>                                                                   tNodeMap;
                tNodeMap m_NodeMap;
            public:
                Type()
                {}
            public:
                ::Wiz::Void::Type Subscribe(const EvtT& E, const tSubscriber* SPtr)
                {
                    this->Subscribe(E, SPtr, &tSubscriber::EventRespond);
                }
                ::Wiz::Void::Type Unsubscribe(const EvtT& E, const tSubscriber* SPtr)
                {
                    this->Unsubscribe(E, SPtr, &tSubscriber::EventRespond);
                }
            public:
                template<class U>
                ::Wiz::Void::Type Subscribe(const EvtT& E, const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(C));
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found == m_NodeMap.End())
                    {
                        Found = m_NodeMap.Insert(E, tNode());
                    }

                    Found.GetValue().Subscribe(C, FP);
                }
                template<class U>
                ::Wiz::Void::Type Unsubscribe(const EvtT& E, const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(C));
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found != m_NodeMap.End())
                    {
                        Found.GetValue().Unsubscribe(C, FP);
                    }
                }
            public:
                ::Wiz::Void::Type EventPublish(const EvtT& E WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
                {
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found != m_NodeMap.End())
					{
						Found.GetValue().EventPublish(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, A));
                    }
                }
            };
        } /// end of namespace Community

        namespace Transfer
        {
            namespace Node
            {
                template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
                class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))> : public ::Wiz::Event::Subscriber::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
                {
                public:
                    typedef typename ::Wiz::Event::Publisher::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>    tPublisher;
                    typedef typename tPublisher::tSubscriber                                                            tSubscriber;
                protected:
                    tPublisher m_Publisher;
                public:
                    Type()
                    {}
                public:
                    ::Wiz::Void::Type Subscribe(const tSubscriber* SPtr)
                    {
                        m_Publisher.Subscribe(SPtr);
                    }
                    ::Wiz::Void::Type Unsubscribe(const tSubscriber* SPtr)
                    {
                        m_Publisher.Unsubscribe(SPtr);
                    }
                public:
                    template<class U>
                    ::Wiz::Void::Type Subscribe(const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                    {
                        WIZ_ASSERT(::Wiz::IsValidPtr(C));
                        m_Publisher.Subscribe(C, FP);
                    }
                    template<class U>
                    ::Wiz::Void::Type Unsubscribe(const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                    {
                        WIZ_ASSERT(::Wiz::IsValidPtr(C));
                        m_Publisher.Unsubscribe(C, FP);
                    }
                public:
                    virtual ::Wiz::Void::Type EventRespond(WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
                    {
                        m_Publisher.EventPublish(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, A));
                    }
                };
            } /// end of namespace Node

            template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
            class Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
            {
            public:
                typedef typename ::Wiz::Event::Agency::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>           tSuper;
                typedef typename ::Wiz::Event::Publisher::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>        tPublisher;
                typedef typename ::Wiz::Event::Transfer::Node::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>   tNode;
                typedef typename tPublisher::tSubscriber                                                                tSubscriber;
                typedef ::Wiz::MultiMap::Type<EvtT, tPublisher*>                                                        tPublisherMap;
                typedef ::Wiz::Map::Type<EvtT, tNode>                                                                   tNodeMap;
            protected:
                tPublisherMap m_PublisherMap;
                tNodeMap m_NodeMap;
            public:
                tPublisherMap& GetPubliserMap()
                {
                    return m_PublisherMap;
                }
            public:
                Type()
                {}
            public:
                ::Wiz::Void::Type Register(const EvtT& E, tPublisher* PPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(PPtr));
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found == m_NodeMap.End())
                    {
                        Found = m_NodeMap.Insert(E, tNode());
                    }
                    PPtr->Subscribe(&(Found.GetValue()));
                    m_PublisherMap.Insert(E, PPtr);
                }
                ::Wiz::Void::Type Unregister(const EvtT& E, tPublisher* PPtr)
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(PPtr));
                    tNodeMap::tIteratorConst FoundNode = m_NodeMap.Find(E);
                    if (FoundNode != m_NodeMap.End())
                    {
                        tPublisherMap::tIterator Itr = m_PublisherMap.LowerBound(E);
                        tPublisherMap::tIteratorConst ItrEnd = m_PublisherMap.UpperBound(E);
                        for (; Itr != ItrEnd; Itr++)
                        {
                            if (Itr.GetValue() == PPtr)
                            {
                                PPtr->Unsubscribe(&(FoundNode.GetValue()));
                                m_PublisherMap.Erase(Itr);
                                return;
                            }
                        }
                    }
                }
            public:
                ::Wiz::Void::Type Subscribe(const EvtT& E, const tSubscriber* SPtr)
                {
                    this->Subscribe(E, SPtr, &tSubscriber::EventRespond);
                }
                ::Wiz::Void::Type Unsubscribe(const EvtT& E, const tSubscriber* SPtr)
                {
                    this->Unsubscribe(E, SPtr, &tSubscriber::EventRespond);
                }
            public:
                template<class U>
                ::Wiz::Void::Type Subscribe(const EvtT& E, const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(C));
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found == m_NodeMap.End())
                    {
                        Found = m_NodeMap.Insert(E, tNode());
                    }
                    Found.GetValue().Subscribe(C, FP);
                }
                template<class U>
                ::Wiz::Void::Type Unsubscribe(const EvtT& E, const U* C, ::Wiz::Void::Type(U::*FP)(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T)))
                {
                    WIZ_ASSERT(::Wiz::IsValidPtr(C));
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found != m_NodeMap.End())
                    {
                        Found.GetValue().Unsubscribe(C, FP);
                    }
                }
            public:
                ::Wiz::Void::Type Receive(const EvtT& E WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
                {
                    tNodeMap::tIterator Found = m_NodeMap.Find(E);
                    if (Found != m_NodeMap.End())
					{
						Found.GetValue().EventRespond(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, A));
                    }
				}
				::Wiz::Void::Type EventPublish(const EvtT& E WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_XY(WIZ_EVENT_PARAM_COUNT, T, A))
				{
					tPublisher* TempPtr;
					tPublisherMap::tIterator Lower = m_PublisherMap.LowerBound(E);
					tPublisherMap::tIteratorConst Upper = m_PublisherMap.UpperBound(E);
					for (; Lower != Upper; Lower++)
					{
						TempPtr = Lower.GetValue();
						WIZ_ASSERT(::Wiz::IsValidPtr(TempPtr));
						(*TempPtr).EventPublish(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, A));
					}
				}
            };
        } /// end of namespace Transfer

        template <class EvtT WIZ_COMMA_IF(WIZ_EVENT_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, class T)>
        struct Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>
        {
            typedef typename ::Wiz::Event::Publisher::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>    tPublisher;
            typedef typename ::Wiz::Event::Subscriber::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>   tSubscriber;
            typedef typename ::Wiz::Event::Agency::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>       tAgency;
            typedef typename ::Wiz::Event::Community::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>    tCommunity;
            typedef typename ::Wiz::Event::Transfer::Type<EvtT(WIZ_ENUM_PARAM_X(WIZ_EVENT_PARAM_COUNT, T))>     tTransfer;
        };
    } /// end of namespace Event
} /// end of namespace Wiz

#endif /* defined(WIZ_EVENT_PARAM_COUNT) && (WIZ_EVENT_PARAM_COUNT >= 0) && (WIZ_EVENT_PARAM_COUNT < 255)*/
